{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 提示词 #\n",
    "from openai import OpenAI\n",
    "\n",
    "client = OpenAI(\n",
    "    #api_key=os.getenv(\"DASHSCOPE_API_KEY\"),\n",
    "    # api_key=\"sk-b571bfbe652b4ec68ac0491e33949622\", # 这种写法不好，泄露了api-key。 回头正式部署时改掉。\n",
    "    # base_url=\"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n",
    "    api_key=\"ollama\",\n",
    "    base_url=\"http://192.168.20.43:11434/v1\"\n",
    ")\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "顾问1:无锡我们现在在天津的话有一个。\n",
      "客户1:海河边海河金茂府，这个房子就是这种的，对，这个是我们。\n",
      "顾问1:金茂府它的一个特别大的一个核心了，我们在全国的第一座金茂府在哪儿？\n"
     ]
    }
   ],
   "source": [
    "# 去除前置符号 #\n",
    "import re\n",
    "def text_format(text):\n",
    "    cleaned_text = re.sub(r'^(?:\\d{2}:\\d{2}:\\d{2} \\d{2}:\\d{2}:\\d{2})\\s', '', text, flags=re.MULTILINE)\n",
    "    return cleaned_text.strip()\n",
    "\n",
    "# 测试代码\n",
    "text = \"\"\"\n",
    "00:01:41 00:01:43 顾问1:无锡我们现在在天津的话有一个。\n",
    "00:01:43 00:01:48 客户1:海河边海河金茂府，这个房子就是这种的，对，这个是我们。\n",
    "00:01:48 00:01:53 顾问1:金茂府它的一个特别大的一个核心了，我们在全国的第一座金茂府在哪儿？\n",
    "\"\"\" \n",
    "new_text = text_format(text)\n",
    "print(new_text)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "from pydantic import BaseModel, Field\n",
    "from typing import List\n",
    "import json\n",
    "\n",
    "class Item(BaseModel):\n",
    "    home_purchase_times: str = Field(..., pattern=\"^(首次|二次|三次及以上|未知)$\", description='必选项：购房次数(本次在该城市的购房次数)')\n",
    "    home_purchase_times_description: str = Field(..., description='推断购房次数的原因')\n",
    "    home_purchase_purpose: str = Field(..., pattern=\"^(商办自用|投资/出租|为子女教育|给子女购房|改善居住环境或居住数量|婚房|给老人/养老购房|首次置业|其他|未知)$\", description='必选项：置业目的,可多选。')\n",
    "    home_purchase_purpose_description: str = Field(..., description='推断置业目的的原因，未说明原因的视为未知。提及名人只是证明该房产有名人效应，并不能说明置业目的。')\n",
    "    home_purchase_needs_to_sell: str = Field(..., pattern=\"^(是|否|未知)$\", description='必选项：本次购房是否需先卖房')\n",
    "    home_purchase_needs_to_sell_description: str = Field(..., description='推断needs_to_sell的原因，未说明原因的视为未知。')\n",
    "    \n",
    "class Purchase_Intent(BaseModel):\n",
    "    home_purchase_intent: str = Field(..., pattern=\"^(强烈意向|中等意向|低意向|无意向)$\", description='必选项：根据客户与置业顾问的对话内容来划分客户的购房意向')\n",
    "    home_purchase_intent_description: str = Field(..., description='判断客户购房意向的具体理由。')\n",
    "\n",
    "class Purchase_Stage(BaseModel):\n",
    "    home_purchase_stage: str = Field(..., pattern=\"^(1/6需求了解阶段|2/6深入讨论阶段|3/6价格谈判阶段|4/6决策阶段|5/6成交阶段|6/6售后服务阶段)$\", description='必选项：判断双方的进展阶段。如果对话内容越来越具体，涉及到的价格和合同细节越来越多，说明双方的进展比较深入。反之，如果对话还停留在基本信息的介绍上，那么进展可能还在早期阶段。')\n",
    "    home_purchase_stage_description: str = Field(..., description='判断双方进展阶段的具体理由。')\n",
    "\n",
    "# 测试代码\n",
    "schema = Item.model_json_schema()\n",
    "formatted_schema = json.dumps(schema, indent=2)\n",
    "# print(formatted_schema)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "def llm_relection_prompt(context_str):\n",
    "    system_prompt = \"\"\n",
    "    prompt = f\"\"\"\\\n",
    "    提取以下对话内容中的关键信息，并按json schema中的约束返回。注意，对话中没提及的客观信息一律按未知处理，不要主观推断。\n",
    "    json schema格式如下：\n",
    "    {Item.model_json_schema()}\n",
    "    Input: {context_str}\n",
    "    Output: \n",
    "    ---------------------\\\n",
    "    \"\"\"\n",
    "    completion = client.chat.completions.create(\n",
    "        model=\"qwen2-7b-instruct\",\n",
    "        messages=[{'role': 'system', 'content': system_prompt},\n",
    "                  {'role': 'user', 'content': prompt}],\n",
    "        )\n",
    "    return completion.choices[0].message.content\n",
    "\n",
    "# 测试用例\n",
    "query1 = \"\"\"\n",
    "顾问1：您好，我注意到您对我们的房产服务感兴趣。首先，我想了解一下您的购房背景。您这是在天津的首次购房吗，还是您已经有过购房记录了？\n",
    "客户1：哦，这是我第二次在天津购房了。\n",
    "顾问1：明白了，那么关于您的置业目的，您是出于什么原因考虑购买新房产的呢？是自住、投资，还是其他什么原因？\n",
    "客户1：主要是为了投资出租，同时也考虑到给子女更好的教育环境。\n",
    "顾问1：这很重要。那么在您购买这个新房产之前，您是否需要先出售现有的房产呢？\n",
    "客户1：是的，我需要先卖掉我现在的房子，才能购买新的。\n",
    "顾问1：好的，这些信息对我们来说非常关键。您这是第二次在天津购房，目的是投资出租和为子女教育。在您购买新房产之前，您需要先卖掉现有的房产。我们会根据您的这些需求，为您提供最合适的房产选项。您提到的海河边的海河金茂府，确实是一个不错的选择。作为我们全国的第一座金茂府，它不仅地理位置优越，而且品质卓越，非常适合您的投资和家庭需求。\n",
    "\"\"\"\n",
    "query2 = \"\"\"\n",
    "00:00:04 00:00:08 顾问1:你好你好先生，我这边销售您好，您是一起的是吧？\n",
    "00:00:08 00:00:13 顾问1:您好，我这边销售是您您和女士。\n",
    "00:00:58 00:01:12 顾问1:不，我们我们是两个部门两个部门，你看像我们是销售是专门接待客户，但是有的时候客户量比较大的情况之下，他们会辅助我们，有的时候客户迎来送货。\n",
    "00:01:12 00:01:16 客户1:这种，不是不是，是我们是我们的。\n",
    "00:01:17 00:01:17 顾问1:对，你看他。\n",
    "00:01:17 00:01:21 客户1:带着工来了，30公分，我们都是金茂员工。\n",
    "00:01:21 00:01:34 顾问1:没问题的，您放心，您喝水之前您来的时候，像现在的水晶体是楼座的模型，是这种模型，但是现在因为卖的差不多了，对。\n",
    "00:01:34 00:01:37 顾问1:您喝楼下一会儿，咱下去可以喝点热的。\n",
    "00:01:37 00:01:39 顾问1:楼上就是瓶装水。\n",
    "00:01:39 00:01:48 顾问1:但是现在说实话卖的是真的差不多了，所以就把这个模型全部换成了小小的这种水晶体。\n",
    "00:01:49 00:01:56 顾问1:像这边的楼是我们目前正在售，并且是我们有大量的房源储备的，二期。\n",
    "00:01:56 00:01:58 顾问1:对，这位是您太太吗？\n",
    "00:01:58 00:02:02 顾问1:好的，我等他，我们一起去说一下。\n",
    "00:02:03 00:02:07 顾问1:您好我您好，我是。\n",
    "00:02:07 00:02:08 客户1:销售。\n",
    "00:02:09 00:02:13 顾问1:对，我们是这样的，因为有时候客户量比较大，先生刚才问。\n",
    "00:02:13 00:02:14 客户1:了我们。\n",
    "00:02:14 00:02:26 顾问1:都是给客户服务的，有的时候来不及我接待完事儿像我们同事御姐，可能您来送往看看样板间是相辅相成的，都是金茂正式的员工，您放心。\n",
    "00:02:27 00:02:30 顾问1:这边对有一个开发商的一个介绍。\n",
    "00:02:31 00:02:32 客户1:对。\n",
    "00:02:34 00:02:35 顾问1:中化。\n",
    "00:02:35 00:02:38 客户1:整体行。\n",
    "00:02:38 00:02:38 顾问1:啥？\n",
    "00:02:38 00:02:43 顾问1:我把位置位置和项目沙盘跟您说一下。\n",
    "00:02:45 00:02:46 客户1:你先看看。\n",
    "00:02:47 00:02:49 顾问1:这个区域要跟您说吗？\n",
    "00:02:49 00:02:50 客户1:区位位置。\n",
    "00:02:50 00:02:51 顾问1:都很熟了\n",
    "00:02:54 00:02:55 顾问1:我就想这个项目。\n",
    "00:02:55 00:02:56 客户1:在哪好？\n",
    "00:02:56 00:03:05 顾问1:我们现在我们现在在配件3，在这个地方在这儿我的激光笔是红色的，上北下南，左西右东，咱们的四志。\n",
    "00:03:05 00:03:12 顾问1:刚才您和太太是从北侧体院北道这儿有一个粉色大玩偶大笑。\n",
    "00:03:12 00:03:16 顾问1:对，从这儿进来的，这个是我们金茂去打造的一个街区。\n",
    "00:03:20 00:03:26 顾问1:麦当劳，及已经开业的星巴克，一共是7300平米。\n",
    "00:03:26 00:03:29 顾问1:我们实际上项目北侧是到哪儿？\n",
    "00:03:29 00:03:35 顾问1:这个位置，就您刚刚停车的地儿，这个是体院道双向单车道华湖中路。\n",
    "00:03:36 00:03:42 顾问1:我们南侧这条路名字可能您都没听过，是特别小的一个路西庄子北道。\n",
    "00:03:42 00:03:50 顾问1:包括西侧这边是集善路，这个是我们整个的4至，那在我们最西侧的位置是大管的方向，就是魏晋南路。\n",
    "00:03:50 00:04:18 顾问1:我们现在站在这边，从我们南侧的红线300米开外黑牛城道，北侧您刚才进来进口位置的公交站以及在这个地方有一个肿瘤医院的一个站点，a出口距离咱们项目走路78分钟左右就能到，这是咱周边。\n",
    "00:04:18 00:04:35 顾问1:那整个项目是原来大学的体育学院，大学静止没有任何不利因素，园林的一个成熟度已经非常好了，但是政府还会再去给它做一个改善，周边是围合的。\n",
    "00:04:36 00:04:56 顾问1:那我们在这个位置也规划了小型的商业，后期咱们的业主您去往湖面休闲娱乐走这个位置6号楼的下面和13号楼下面两个小门儿，咱们的对，你像这么大的面积。\n",
    "00:04:58 00:04:59 客户1:对。\n",
    "00:04:59 00:05:03 顾问1:要修，前一阵儿咱们不属于天塔街道嘛？\n",
    "00:05:04 00:05:05 顾问1:就是政府的一些领导。\n",
    "00:05:06 00:05:07 客户1:河西区。\n",
    "00:05:07 00:05:08 顾问1:河西区。\n",
    "00:05:08 00:05:11 顾问1:对，河西天塔附近，咱的天塔街道。\n",
    "00:05:11 00:05:13 顾问1:对。\n",
    "00:05:14 00:05:14 客户1:因为。\n",
    "00:05:15 00:05:21 顾问1:西青了，像这不是快速路嘛，南侧一半河西一半西青，就是老梅江。\n",
    "00:05:21 00:05:24 顾问1:对，这边是属于河西。\n",
    "00:05:24 00:05:35 顾问1:我们项目您看一下，我们现在不是在这儿嘛，配件3，它是一个大的中轴线，一个景观廊，对，整个项目以它以条线为例，一分为二。\n",
    "00:05:35 00:05:52 顾问1:现在您看到所有的楼型的模型的位置是我们的二期，是我们的二期，一期是水晶体，看起来矮一些，但是它也是跟这边一样高度的小高层，17层的高层，25层的。\n",
    "00:05:53 00:05:57 顾问1:对，是因为它卖的差不多了，所以就把它的模型换了一下。\n",
    "00:05:58 00:06:28 顾问1:对，一期是去年年底开的盘，其实也就90个月左右，这个项目因为它本身定位再加上咱金茂府的一个定位，它是纯做高端改善住宅，整个来讲的话呢这个圈层定位、产品定位都是比较高的，所以周边的话您要是在周边住，应该也知道没有什么图谱，现在都集中中性的往这个社区来了，就这样一个情况，现在卖的是非常好的。\n",
    "00:06:28 00:06:32 顾问1:我们现在二期楼座相对比较较多，但是面积较大。\n",
    "00:06:32 00:06:47 顾问1:我整体的跟您说一下我们的规划，你看这个位置，像这个是东南金角这几栋楼规划的是128的面积，但是现在就128，基本上没有什么可选性。\n",
    "00:06:50 00:07:15 顾问1:18号楼1楼、顶楼就是这种房源，对，然后就是这三套房，但是虽然可选性不多，价格上咱也有一定的优势，很合适这128标准的3室2厅2卫，然后4号楼您看一下，您可以这边挪步，4号楼现在是在您刚才进口停车的位置，能看得见的一个位置。\n",
    "00:07:16 00:07:18 顾问1:地铁什么的都是最方便的。\n",
    "00:07:19 00:07:21 顾问1:我北侧一排的这个楼。\n",
    "\n",
    "\"\"\"\n",
    "query3 = \"\"\"\n",
    "00:35:04 00:35:08 客户1:这个没有，对，这块是空的，但是这个门，对。\n",
    "00:35:08 00:35:10 客户1:但是墙面也是这样墙面，对。\n",
    "00:35:16 00:35:39 顾问1:厨房您看一下，像这个方太的烟机方太的烟机、灶具、洗碗机、摩恩的五金拉式的水龙头，在这儿交房的时候还会有直饮水，下面这个位置是拼特尔的直饮水，还有这个红色的是贝克巴斯的垃圾处理器，都在我们交付范围。\n",
    "00:35:40 00:35:51 顾问1:在这儿您看一下，有一个出风口，这是我的新风出风口，就您做饭的时候第一，我的烟机是空调式的，不会很不过夏天也不会很热，本来就是恒温的，舒温的。\n",
    "00:35:52 00:35:58 顾问1:这儿有新风，它随时都是在回收一些异味、烟味、油烟这种。\n",
    "00:35:58 00:35:58 顾问1:对。\n",
    "00:35:59 00:36:04 顾问1:包括像所有的吊柜所有的这些吊柜、所有的地柜都是在我们的。\n",
    "00:36:04 00:36:08 客户1:交付上，对别想。\n",
    "00:36:09 00:36:11 顾问1:冰箱吗？\n",
    "00:36:11 00:36:20 顾问1:冰箱没在我们的交付范围，但是我们在这儿也会给你预留一个冰箱位，它正常的双开门的冰箱是可以放的，你要超大的，可能是贝拉金。\n",
    "00:36:24 00:36:34 客户1:对，就这173的，对吧？\n",
    "00:36:34 00:36:41 客户1:你明显从外面的科技馆。\n",
    "00:36:47 00:36:49 顾问1:这沙发还可以再往前。\n",
    "00:36:49 00:36:50 顾问1:感受。\n",
    "00:36:50 00:36:50 客户1:一下。\n",
    "00:36:58 00:36:59 客户1:这房子总价多少钱？\n",
    "00:36:59 00:37:00 顾问1:看看这。\n",
    "00:37:00 00:37:01 客户1:套房子是吗？\n",
    "00:37:02 00:37:07 客户1:咱可以先看这套房子还款是750到180。\n",
    "00:37:08 00:37:13 顾问1:这是阳台这个是阳台，您看一下。\n",
    "00:37:14 00:37:15 客户1:到。\n",
    "00:37:15 00:37:16 顾问1:这儿其实。\n",
    "00:37:22 00:37:30 客户1:还是还贷的这个第四代是。\n",
    "00:37:30 00:37:32 顾问1:空的没有这个了。\n",
    "00:37:32 00:37:33 顾问1:但是。\n",
    "00:37:33 00:37:34 客户1:篮板对，篮板。\n",
    "00:37:34 00:37:35 顾问1:会高一些，大概到。\n",
    "00:37:35 00:37:37 客户1:这儿，对。\n",
    "00:37:37 00:37:38 顾问1:对。\n",
    "00:37:39 00:37:41 客户1:你这就对就对的，就往哪录了？\n",
    "00:37:43 00:37:44 客户1:不是，南路小区。\n",
    "00:37:49 00:37:57 顾问1:但是交房了之后，其实您在阳台上去做一些园林小型的造景，做出来之后其实就还好。\n",
    "00:37:57 00:38:23 顾问1:因为天津说实话雨水其实还好，你就是我我认为啊，因为我们6号楼、3楼其实当时下雨的时候只没有进水，唯一就是可能雨雪的时候只没有进水，唯一就是可能雨雪的时候打扫起来至少也很方便，而且最主要是它。\n",
    "00:38:26 00:38:27 客户1:这带。\n",
    "00:38:27 00:38:27 顾问1:阳面。\n",
    "00:38:27 00:38:30 客户1:上面顶子是有。\n",
    "00:38:30 00:38:35 顾问1:顶子有的其实它没有您想那么容易进水，真的就是像到这个位置。\n",
    "00:38:36 00:38:42 客户1:心里那净水那也是特殊，他那个上海的台风。\n",
    "00:38:43 00:38:46 顾问1:南南方南方进水很正常，您知道为啥吗？\n",
    "00:38:46 00:38:53 顾问1:南方它的阳台面宽做的很大，第二一个是像上海江浙，它的雨水多。\n",
    "00:38:53 00:38:57 顾问1:第三一个先生刚才说的，它会有一些台风。\n",
    "00:38:57 00:38:58 顾问1:对，那个是难以避免。\n",
    "00:38:59 00:39:04 客户1:的不实用，晾衣服都不行。\n",
    "00:39:04 00:39:05 顾问1:晾衣服您在。\n",
    "00:39:05 00:39:14 客户1:这晾不能户外晾，看看门子这个大的，不说下的知道就是封不起来。\n",
    "00:39:14 00:39:18 客户1:它要能封起来，所以我晚上看。\n",
    "\"\"\"\n",
    "# 测试\n",
    "# context_str = text_format(query)\n",
    "# summary_text = llm_relection_prompt(context_str) \n",
    "# print(summary_text)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "### 意图识别 ###\n",
    "def llm_intent_prompt(context_str):\n",
    "    system_prompt = f\"\"\"\n",
    "    请根据客户与置业顾问的对话内容来划分客户的购房意向。以下是四个档次的划分标准：\n",
    "\n",
    "    1. 强烈意向（High Intent）\n",
    "    - 行为：客户主动联系并频繁询问房产细节，表现出浓厚的兴趣，愿意投入时间进行多次看房。\n",
    "    - 语言：使用肯定的语言，对购房流程和条件表现出明确的认同和接受。\n",
    "    - 态度：表现出紧迫感，希望尽快完成交易，对价格谈判持开放态度。\n",
    "\n",
    "    2. 中等意向（Medium Intent）\n",
    "    - 行为：对房产有一定的兴趣，定期询问更新信息，但不会频繁跟进。\n",
    "    - 语言：语言较为中立，可能会提出一些条件或要求，但不会过于坚持。\n",
    "    - 态度：对购房有一定的兴趣，但可能还在观望市场或比较其他选项。\n",
    "\n",
    "    3. 低意向（Low Intent）\n",
    "    - 行为：对房产的询问较少，且不经常跟进，可能只是出于好奇或随便看看。\n",
    "    - 语言：语言较为消极或模糊，可能对房产的某些方面表示不满或不感兴趣。\n",
    "    - 态度：对购房没有紧迫感，可能只是收集信息，没有立即购买的打算。\n",
    "\n",
    "    4. 无意向（No Intent）\n",
    "    - 行为：对房产完全不感兴趣，不会主动询问或跟进，可能很快就结束了对话。\n",
    "    - 语言：明确表示没有购买意向，可能对房产的任何方面都不感兴趣。\n",
    "    - 态度：对购房没有任何紧迫感，也没有收集信息的意愿。\n",
    "\n",
    "    请根据上述标准，分析以下对话内容，并划分客户的购房意向档次。按如下json schema格式输出，不要输出任何其它内容。\n",
    "    {Purchase_Intent.model_json_schema()}\n",
    "\n",
    "    Input: {context_str}\n",
    "    Output: \n",
    "    \"\"\"\n",
    "    prompt = \"\"\n",
    "    completion = client.chat.completions.create(\n",
    "        model=\"qwen2-7b-instruct\",\n",
    "        messages=[{'role': 'system', 'content': system_prompt},\n",
    "                  {'role': 'user', 'content': prompt}],\n",
    "        )\n",
    "    return completion.choices[0].message.content\n",
    "\n",
    "# 测试代码\n",
    "# context_str = text_format(query2)\n",
    "# intent = llm_intent_prompt(context_str) \n",
    "# print(intent)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "尽量让客户多问、多说，学会聆听，合理分析客户问题。以下是双方话语权占比：\n",
      "\n",
      "话语权占比：\n",
      "顾问1话语权占比：95.52%\n",
      "客户1话语权占比：4.48%\n"
     ]
    }
   ],
   "source": [
    "# 话语权占比 #\n",
    "\n",
    "def count_characters(dialogue):\n",
    "    # 按行分割对话，获取每个人的发言\n",
    "    lines = dialogue.strip().split('\\n')\n",
    "    \n",
    "    # 初始化计数器\n",
    "    speaker_counts = {}\n",
    "    \n",
    "    # 遍历每一行，根据标签累加字符数\n",
    "    for line in lines:\n",
    "        # print(f\"line: {line}\")\n",
    "        # 查找第一个冒号的位置\n",
    "        colon_index = line.find(':')\n",
    "        # 检查冒号前是否有其他冒号，确保冒号是行中的第一个冒号\n",
    "        if colon_index != -1 and line[:colon_index].count(':') == 0:\n",
    "            speaker = line[:colon_index].strip()  # 去除可能的前后空格\n",
    "            # print(f\"speaker: {speaker}\")\n",
    "            speech = line[colon_index+1:].strip()  # 去除可能的前后空格\n",
    "            # print(f\"speech: {speech}\")\n",
    "            if speaker in speaker_counts:\n",
    "                speaker_counts[speaker] += len(speech)\n",
    "            else:\n",
    "                speaker_counts[speaker] = len(speech)\n",
    "    # 计算总字符数\n",
    "    total_characters = sum(speaker_counts.values())\n",
    "    \n",
    "    # 计算话语权占比\n",
    "    percentage = {speaker: (count / total_characters * 100) for speaker, count in speaker_counts.items()}\n",
    "    \n",
    "    # 返回说话者及其对应的字符数和话语权占比\n",
    "    return speaker_counts, percentage\n",
    "\n",
    "#测试代码\n",
    "dialogue = text_format(query2)\n",
    "speaker_counts, percentages = count_characters(dialogue)\n",
    "print(\"尽量让客户多问、多说，学会聆听，合理分析客户问题。以下是双方话语权占比：\")\n",
    "print(\"\\n话语权占比：\")\n",
    "for speaker, percent in percentages.items():\n",
    "    print(f\"{speaker}话语权占比：{percent:.2f}%\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "```json\n",
      "{\n",
      "  \"home_purchase_stage\": \"2/6深\n",
      "入讨论阶段\",\n",
      "  \"home_purchase_stage_descripti\n",
      "on\": \"在对话中，置业顾问详细介绍了项目的地理位置、区位优势、周边设施、规划\n",
      "、楼型以及价格等信息。客户对此表现出兴趣，并询问了具体的细节，比如销售接待流程、\n",
      "项目定位、楼座分布和户型选择等。双方的讨论已经从基本信息转向更为具体的内容，显示\n",
      "出了较高的互动深度，因此判断对话处于深入讨论阶段。\"\n",
      "}\n",
      "```\n"
     ]
    }
   ],
   "source": [
    "### 推进阶段识别 ###\n",
    "def llm_stage_prompt(context_str):\n",
    "    system_prompt = f\"\"\"\n",
    "    请根据客户与置业顾问的对话内容来推断双方的进展。以下是六个阶段的划分标准：\n",
    "\n",
    "    1.需求了解阶段：\n",
    "    客户询问关于房产的基本信息，如位置、价格、户型等。\n",
    "    置业顾问提供房产的基本信息和特点。\n",
    "    对话内容较为基础，没有涉及到具体的购买意向。\n",
    "\n",
    "    2.深入讨论阶段：\n",
    "    客户开始询问更详细的问题，比如贷款政策、税费、交房时间等。\n",
    "    置业顾问提供更具体的信息，并开始根据客户的需求推荐特定的房产。\n",
    "    对话内容开始涉及客户的个人情况和偏好。\n",
    "\n",
    "    3.价格谈判阶段：\n",
    "    客户对某套房产表现出兴趣，并开始询问价格优惠、付款方式等。\n",
    "    置业顾问可能会提供一些优惠政策或者建议不同的付款方案。\n",
    "    对话中开始出现价格上的讨论和协商。\n",
    "    \n",
    "    4.决策阶段：\n",
    "    客户表现出明确的购买意向，可能会要求看房或者再次确认房产的细节。\n",
    "    置业顾问会安排看房时间或者提供更多的房产证明文件。\n",
    "    对话内容更加具体，涉及到合同条款和下一步的行动计划。\n",
    "    \n",
    "    5.成交阶段：\n",
    "    客户决定购买，并开始讨论合同细节、交款事宜等。\n",
    "    置业顾问准备合同文件，协助客户完成购买流程。\n",
    "    对话内容涉及到具体的法律文件和交易流程。\n",
    "    \n",
    "    6.售后服务阶段：\n",
    "    客户已经完成购买，开始询问关于房产的后续服务，如装修、物业管理等。\n",
    "    置业顾问提供售后服务信息，确保客户满意度。\n",
    "    对话内容转向售后服务和客户关怀。\n",
    "\n",
    "    通过对话内容的深度和具体性，可以大致判断双方的进展。如果对话内容越来越具体，涉及到的价格和合同细节越来越多，说明双方的进展比较深入。反之，如果对话还停留在基本信息的介绍上，那么进展可能还在早期阶段。\n",
    "    请根据上述标准，分析以下对话内容，判断双方进展到哪个阶段。按如下json schema格式输出，不要输出任何其它内容。\n",
    "    {Purchase_Stage.model_json_schema()}\n",
    "\n",
    "    Input: {context_str}\n",
    "    Output: \n",
    "    \"\"\"\n",
    "    prompt = \"\"\n",
    "    completion = client.chat.completions.create(\n",
    "        model=\"qwen2-7b-instruct\",\n",
    "        messages=[{'role': 'system', 'content': system_prompt},\n",
    "                  {'role': 'user', 'content': prompt}],\n",
    "        )\n",
    "    return completion.choices[0].message.content\n",
    "\n",
    "def print_with_fixed_length(text, line_length=50):\n",
    "    # 将长文本按固定长度分割成多行\n",
    "    for i in range(0, len(text), line_length):\n",
    "        print(text[i:i + line_length])\n",
    "\n",
    "# 测试代码\n",
    "context_str = text_format(query2)\n",
    "stage = llm_stage_prompt(context_str) \n",
    "print_with_fixed_length(stage, line_length=40)  # 这里设置每行最多50个字符"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
